/*
 *  ifxparams.cpp - Informix parameter classes for dbExpress implementation
 *
 *    Copyright (c) 2001-2006, Luxena Software Company. All rights reserved.
 *
 *  Purpose:
 *
 */

#include "ifxparams.hpp"

#include <new>
#include <ifxtypes.h>
#include "ifxerror.hpp"
#include "ifxvariable.hpp"


/////////////////////////////////////////////////////////////////////////////
// CInformixParameters

CInformixParameters::CInformixParameters (int2 count)
{
	if ((sqld = count) == 0) {
		sqlvar = 0;
		return;
	}

	sqlvar = new ifx_sqlvar_t [count];
	memset(sqlvar, 0, count*sizeof(ifx_sqlvar_t));

	(_variables = new CInformixVariable [count])--;

	ifx_sqlvar_t *sqlvar = this->sqlvar;
	CInformixVariable *variable = _variables;
	for (int i = 0; i < count; i++)
		(++variable)->initialize(sqlvar++);
}

CInformixParameters::~CInformixParameters ()
{
	if (getCount() == 0)
		return;
    delete [] ++_variables;
    delete [] sqlvar;
}

int2 CInformixParameters::getCount ()
{
    return sqld;
}

CInformixVariable& CInformixParameters::operator [] (int2 number)
{
    return _variables[number];
}


/////////////////////////////////////////////////////////////////////////////
// CInformixParameterValueFactory

CInformixParameterValueFactory::ValueCreatorFunc CInformixParameterValueFactory::ValueCreatorTable[] =
{
	CInformixParameterValueFactory::handleUnsupported,       // fldUNKNOWN
	CInformixParameterValueFactory::createStringValue,       // fldZSTRING
	CInformixParameterValueFactory::createDateValue,         // fldDATE
	CInformixParameterValueFactory::createBlobValue,         // fldBLOB
	CInformixParameterValueFactory::createBoolValue,         // fldBOOL
	CInformixParameterValueFactory::createShortValue,        // fldINT16
	CInformixParameterValueFactory::createLongValue,         // fldINT32
	CInformixParameterValueFactory::createFloatValue,        // fldFLOAT
	CInformixParameterValueFactory::createBCDValue,          // fldBCD
	CInformixParameterValueFactory::handleUnsupported,       // fldBYTES
	CInformixParameterValueFactory::createTimeValue,         // fldTIME
	CInformixParameterValueFactory::createTimeStampValue,    // fldTIMESTAMP
	CInformixParameterValueFactory::createShortValue,        // fldUINT16
	CInformixParameterValueFactory::createLongValue,         // fldUINT32
	CInformixParameterValueFactory::handleUnsupported,       // fldFLOATIEEE
	CInformixParameterValueFactory::handleUnsupported,       // fldVARBYTES
	CInformixParameterValueFactory::handleUnsupported,       // fldLOCKINFO
	CInformixParameterValueFactory::handleUnsupported,       // fldCURSOR
	CInformixParameterValueFactory::handleUnsupported,       // fldINT64
	CInformixParameterValueFactory::handleUnsupported,       // fldUINT64
	CInformixParameterValueFactory::handleUnsupported,       // fldADT
	CInformixParameterValueFactory::handleUnsupported,       // fldARRAY
	CInformixParameterValueFactory::handleUnsupported,       // fldREF
	CInformixParameterValueFactory::handleUnsupported,       // fldTABLE
	CInformixParameterValueFactory::createDateTimeValue,     // fldDATETIME
	CInformixParameterValueFactory::createBCDValue           // fldFMTBCD
};

CInformixAbstractValue * CInformixParameterValueFactory::createValue (const CInformixParameterValueFactory::Args& args)
{
	if (args.paramType != paramIN)
		throw CInvalidParameterTypeError();

	const int VALUE_CREATOR_TABLE_SIZE = sizeof(ValueCreatorTable) / sizeof(ValueCreatorFunc);

	if (args.dataType.logType < VALUE_CREATOR_TABLE_SIZE)
		return ValueCreatorTable[args.dataType.logType](args);
	else
		return handleUnsupported(args);
}

CInformixAbstractValue * CInformixParameterValueFactory::handleUnsupported (const CInformixParameterValueFactory::Args& args)
{
	char buffer[1024];
	sprintf(buffer, "Data type %d (subtype %d) is unsupported", args.dataType.logType, args.dataType.subType);
	throw CInformixDriverError(buffer);
}

CInformixAbstractValue * CInformixParameterValueFactory::createStringValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixStringValue<SQLCHAR>(args.length, reinterpret_cast<char *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createDateValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixDateValue(*reinterpret_cast<int4 *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createBlobValue (const CInformixParameterValueFactory::Args& args)
{
	switch (args.dataType.subType)
	{
	case fldstMEMO:
		return new CInformixSimpleLOValue<SQLTEXT>(args.length, args.buffer);

	case fldstOLEOBJ:
	case fldstGRAPHIC:
	case fldstDBSOLEOBJ:
	case fldstACCOLEOBJ:
	case fldstBINARY:
		return new CInformixSimpleLOValue<SQLBYTES>(args.length, args.buffer);

	case fldstFMTMEMO:
		return new CInformixLVarCharPtrValue(args.length, args.buffer);

	case fldstHMEMO:
	case fldstHBINARY:
		{
			CInformixActivityPtr activity = args.connection->activate(false, true);
			if (args.dataType.subType == fldstHMEMO)
				return new CInformixCLOBValue(args.length, args.buffer);
			else
				return new CInformixBLOBValue(args.length, args.buffer);
		}

	default:
		return handleUnsupported(args);
	}
}

CInformixAbstractValue * CInformixParameterValueFactory::createBoolValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixBooleanValue(*reinterpret_cast<bool *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createShortValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixSimpleValue<int2, SQLSMINT>(*reinterpret_cast<int2 *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createLongValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixSimpleValue<int4, SQLINT>(*reinterpret_cast<int4 *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createFloatValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixSimpleValue<double, SQLFLOAT>(*reinterpret_cast<double *>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createBCDValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixDecimalValue<SQLDECIMAL>(reinterpret_cast<pFMTBcd>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createTimeValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixDateTimeValue(*reinterpret_cast<pINT32>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createTimeStampValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixDateTimeValue(*reinterpret_cast<pDFLOAT>(args.buffer));
}

CInformixAbstractValue * CInformixParameterValueFactory::createDateTimeValue (const CInformixParameterValueFactory::Args& args)
{
	return new CInformixDateTimeValue(reinterpret_cast<pCTIMESTAMP>(args.buffer));
}
